package com.cnpc.netty.transfer;

import java.util.List;
import java.util.concurrent.ExecutionException;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.MessageToMessageDecoder;

public class Transfer {

	public static int udpport;
	public static String tcpip;
	public static int tcpport;
	static Bootstrap boot;
	static EventLoopGroup group;
	static EventLoopGroup tcpGroup;
	static Bootstrap tcpBoot;
	static Channel udpc;
	static Channel tcpc;

	public Transfer(Integer udpport, String tcpip, Integer tcpport) {
		Transfer.udpport = udpport;
		Transfer.tcpip = tcpip;
		Transfer.tcpport = tcpport;
	}

	public void close() {
		Transfer.udpc.close();
		Transfer.tcpc.close();
	}

	public void start() {
		group = new NioEventLoopGroup();
		boot = new Bootstrap();

		((Bootstrap) ((Bootstrap) ((Bootstrap) ((Bootstrap) ((Bootstrap) ((Bootstrap) boot.group(group))
				.channel(NioDatagramChannel.class)).option(ChannelOption.SO_BROADCAST, Boolean.valueOf(true)))
						.option(ChannelOption.SO_REUSEADDR, Boolean.valueOf(true))).handler(getInitHandle()))
								.handler(getDataDecoder())).handler(getDataHandler());
		ChannelFuture f = boot.bind(udpport).awaitUninterruptibly();
		udpc = f.channel();
		try {
			f.get();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		TcpConnection tcpConnection = new TcpConnection();
		tcpConnection.connect(Transfer.tcpip, Transfer.tcpport);

		/*
		 * EventLoopGroup tcpGroup = new NioEventLoopGroup(); tcpBoot = new Bootstrap();
		 * try { ((Bootstrap) ((Bootstrap)
		 * tcpBoot.group(tcpGroup)).channel(NioSocketChannel.class)) .handler(new
		 * ChannelInitializer() { protected void initChannel(Channel arg0) throws
		 * Exception { ChannelPipeline pipeline = arg0.pipeline();
		 * pipeline.addLast("decoder", new ByteArrayDecoder());
		 * pipeline.addLast("encoder", new ByteArrayEncoder()); } }); // 设置TCP协议的属性
		 * tcpBoot.option(ChannelOption.SO_KEEPALIVE, true);
		 * tcpBoot.option(ChannelOption.TCP_NODELAY, true);
		 * tcpBoot.option(ChannelOption.SO_TIMEOUT, 5000);
		 * 
		 * Transfer.tcpc = Transfer.tcpBoot.connect(Transfer.tcpip,
		 * Transfer.tcpport).sync().channel(); } catch (Exception e) {
		 * e.printStackTrace(); }
		 */
	}

	public InitHandle getInitHandle() {
		return new InitHandle();
	}

	public DataHandler getDataHandler() {
		return new DataHandler();
	}

	public DataDecoder getDataDecoder() {
		return new DataDecoder();
	}

	public class DataDecoder extends MessageToMessageDecoder<DatagramPacket> {
		public DataDecoder() {
		}

		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
			System.out.println("run decoder exceptionCaught");
			super.exceptionCaught(ctx, cause);
		}

		protected void decode(ChannelHandlerContext arg0, DatagramPacket arg1, List<Object> arg2) throws Exception {
			System.out.println(arg1.toString() + "dec");
		}
	}

	public class DataHandler extends SimpleChannelInboundHandler<String> {
		public DataHandler() {
		}

		protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws Exception {
			System.out.println("run handle read0  " + arg1);
		}

		public void channelRead(ChannelHandlerContext arg0, Object arg1) throws Exception {

			DatagramPacket packet = (DatagramPacket) arg1;
			ByteBuf buf = (ByteBuf) packet.content();
			byte[] bb = new byte[buf.readableBytes()];
			buf.readBytes(bb);

			//Transfer.tcpc ==null 说明TCP client未启动，直接不往TCP写入包，丢弃此包 （可优化用其他方式判断，目前这样没问题）
			if(Transfer.tcpc != null){
				Transfer.tcpc.writeAndFlush(bb);
			}
			
			//Transfer.tcpc.close();
			super.channelRead(arg0, arg1);
		}

		public void channelActive(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle active");
			super.channelActive(ctx);
		}

		public void channelInactive(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle inActive");
			super.channelInactive(ctx);
		}

		public boolean acceptInboundMessage(Object msg) throws Exception {
			return super.acceptInboundMessage(msg);
		}

		public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle channelReadComplete");
			super.channelReadComplete(ctx);
			ctx.flush();
		}

		public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle channelRegistered");
			super.channelRegistered(ctx);
		}

		public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle channelUnregistered");
			super.channelUnregistered(ctx);
		}

		public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
			System.out.println("run handle channelWritabilityChanged");
			super.channelWritabilityChanged(ctx);
		}
	}

	public class InitHandle extends ChannelInitializer {
		public InitHandle() {
		}

		protected void initChannel(Channel arg0) throws Exception {
			System.out.println("init");
		}
	}
}